package com.boarsoft.boar.office.work.action;

import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.boarsoft.bean.LogonI;
import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.common.Constants;
import com.boarsoft.boar.office.entity.OfficeGroupUser;
import com.boarsoft.boar.office.entity.OfficeWorkInfo;
import com.boarsoft.boar.office.entity.OfficeWorkLog;
import com.boarsoft.boar.office.group.OfficeGroupUserBiz;
import com.boarsoft.boar.office.work.OfficeWorkBiz;
import com.boarsoft.boar.office.work.biz.OfficeWorkLogBizImpl;
import com.boarsoft.boar.soagov.entity.SvcInfo;
import com.boarsoft.boar.soagov.svc.SvcInfoService;
import com.boarsoft.common.Authorized;
import com.boarsoft.common.Util;
import com.boarsoft.common.dao.PagedResult;
import com.boarsoft.common.util.DateUtil;
import com.boarsoft.common.util.RandomUtil;
import com.boarsoft.flow.core.SimpleFlow;
import com.boarsoft.flow.core.SimpleFlowEngine;
import com.boarsoft.web.controller.BaseController;
import com.boarsoft.web.login.Logined;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@Component
@RestController
@RequestMapping("/work")
public class OfficeWorkAction extends BaseController {
	private static final Logger log = LoggerFactory.getLogger(OfficeWorkAction.class);

	@Autowired
	private OfficeWorkBiz officeWorkBiz;
	@Autowired
	private OfficeGroupUserBiz groupUserBiz;
	@Autowired
	private OfficeWorkLogBizImpl officeWorkLogBiz;

	@Autowired
	private SimpleFlowEngine flowEngine;

	@Autowired
	private SvcInfoService svcInfoService;

	/**
	 * 激活任务：创建并启动工作流
	 * 
	 * @param o
	 * @return
	 */
	@Authorized(code = "office.work.submit")
	@RequestMapping("/submit.do")
	public ReplyInfo<Object> submit(OfficeWorkInfo o) {
		String flowId2 = o.getFlowId2();
		if (Util.strIsEmpty(flowId2)) {
			String flowId = o.getFlowId();
			// 无对应的工作流则直接更新任务状态
			if (Util.strIsEmpty(flowId)) {
				o.setStatus(OfficeWorkInfo.STATUS_RUNNING);
				officeWorkBiz.update(o);
				return ReplyInfo.SUCCESS;
			}
			SvcInfo s = svcInfoService.get(flowId);
			// 有对应的工作流则创建工作流
			String flowExeId = RandomUtil.randomUUID();
			o.setFlowExeId(flowExeId);
			try {
				// 创建并启动流程
				SimpleFlow fo = flowEngine.create(s.getCode());
				fo.setId(flowExeId);
				fo.setData(o);
				flowEngine.start(fo);
				// 更新任务状态
				o.setStatus(OfficeWorkInfo.STATUS_RUNNING);
				officeWorkBiz.update(o);
				// 此时的fo.data是bizDesign任务
				return new ReplyInfo<Object>(true, fo.getData());
			} catch (Throwable e) {
				log.error("Error on start flow {}", flowId, e);
				return Constants.REPLY_ERROR_INTERNAL;
			}
		} else {
			// 续跑关联的任务
			String flowExeId2 = o.getFlowExeId2();
			if (Util.strIsEmpty(flowExeId2)) {
				return Constants.REPLY_WARN_INVALID;
			}
			try {
				SimpleFlow fo = flowEngine.resume(flowId2, flowExeId2, o);
				// 更新任务状态
				o.setStatus(OfficeWorkInfo.STATUS_RUNNING);
				officeWorkBiz.update(o);
				return new ReplyInfo<Object>(true, fo.getData());
			} catch (Throwable e) {
				log.error("Error on resume flow {}/{}", flowId2, flowExeId2, e);
				return Constants.REPLY_ERROR_INTERNAL;
			}
		}
	}

	@RequestMapping("/after.do")
	@Authorized(code = "office.work.after")
	public ReplyInfo<Object> after(String workId, String afterWorkId) {
		OfficeWorkInfo a = officeWorkBiz.get(afterWorkId);
		Date ped = Util.str2date(a.getPlanEndDate());
		Date psd = Util.str2date(a.getPlanStartDate());
		// 计算计划工期（天）
		int b = DateUtil.getDaysBetween(ped, psd);
		OfficeWorkInfo o = officeWorkBiz.get(workId);
		o.setAfterWorkId(afterWorkId);
		o.setLastTime(Util.getStdfDate());
		Date d = null;
		if (Util.strIsEmpty(a.getActualEndDate())) {
			d = Util.str2date(a.getPlanEndDate());
		} else {
			d = Util.str2date(a.getActualEndDate());
		}
		// 计算新的计划开始时间
		d = DateUtil.addDay(d, 1);
		o.setPlanStartDate(Util.date2str(d));
		// 新的计划开始时间 + 计划工期 = 新的计划结束时间
		o.setPlanEndDate(Util.date2str(DateUtil.addDay(d, b)));
		officeWorkBiz.update(o);
		return ReplyInfo.SUCCESS;
	}

	@RequestMapping("/get.do")
	@Authorized(code = "office.work.get")
	public ReplyInfo<Object> get(String id) {
		OfficeWorkInfo o = officeWorkBiz.get(id);
		for (OfficeWorkInfo p : o.getPreWorks()) {
			p.setPreWorks(null);
		}
		o.setOwner(this.getSysUser(o.getOwnerId()));
		if (Util.strIsNotEmpty(o.getFlowId())) {
			o.setFlow(svcInfoService.get(o.getFlowId()));
		}
		return new ReplyInfo<Object>(true, o);
	}

	@RequestMapping("/save.do")
	@Authorized(code = "office.work.save")
	public ReplyInfo<Object> save(@Validated OfficeWorkInfo o, String preWorkIds) {
		boolean resume = false;
		if (o.getStatus() == OfficeWorkInfo.STATUS_DRAFT) {
			if (Util.strIsEmpty(o.getPlanStartDate())) {
				if (Util.strIsEmpty(o.getPlanEndDate())) {
					o.setStatus(OfficeWorkInfo.STATUS_PENDING);
				} else {
					return Constants.REPLY_WARN_INVALID;
				}
			} else {
				if (Util.strIsEmpty(o.getPlanEndDate())) {
					return Constants.REPLY_WARN_INVALID;
				}
				// 任务已排期，未启动（未实际执行）
				o.setStatus(OfficeWorkInfo.STATUS_PENDING);
				resume = true;
			}
		} else {
			if (Util.strIsEmpty(o.getActualStartDate())) {
				if (Util.strIsEmpty(o.getActualEndDate())) {
					o.setStatus(OfficeWorkInfo.STATUS_PENDING);
				} else {
					return Constants.REPLY_WARN_INVALID;
				}
			} else {
				if (Util.strIsEmpty(o.getActualEndDate())) {
					if (o.getProgress() == 100) {
						o.setActualEndDate(Util.getStdfDate());
						o.setStatus(OfficeWorkInfo.STATUS_DONE);
						resume = true;
					} else {
						o.setStatus(OfficeWorkInfo.STATUS_RUNNING);
					}
				} else {
					o.setStatus(OfficeWorkInfo.STATUS_DONE);
					o.setProgress(new Integer(100).shortValue());
					resume = true;
				}
			}
		}
		if (Util.strIsNotEmpty(o.getId())) {
			OfficeWorkInfo a = officeWorkBiz.get(o.getId());
			// 如果有afterWorkId则检查新的计划开始时间或实际开始时间的最小值是否小于原来两者的最小值
			if (Util.strIsNotEmpty(a.getAfterWorkId())) {
				// 如果修改了计划开始时间，且计划开始时间小于前一任务
				Date d2 = Util.str2date(o.getPlanStartDate());
				Date d1 = Util.str2date(a.getPlanStartDate());
				if (d2.getTime() <= d1.getTime()) {
					o.setAfterWorkId(null);
				}
			}
		}
		// 如果是，则删除afterWorkId，解除后继关系
		officeWorkBiz.save(o, preWorkIds);

		// 如果任务完成了，则推动关联的流程继续
		String flowId2 = o.getFlowId2();
		if (resume && Util.strIsNotEmpty(flowId2)) {
			// 续跑关联的任务
			String flowExeId2 = o.getFlowExeId2();
			if (Util.strIsEmpty(flowExeId2)) {
				return Constants.REPLY_WARN_INVALID;
			}
			try {
				SimpleFlow fo = flowEngine.resume(flowId2, flowExeId2, o);
				return new ReplyInfo<Object>(true, fo.getData());
			} catch (Throwable e) {
				log.error("Error on resume flow {}/{}", flowId2, flowExeId2, e);
				return Constants.REPLY_ERROR_INTERNAL;
			}
		}
		return ReplyInfo.SUCCESS;
	}

	@RequestMapping("/cancel.do")
	@Authorized(code = "office.work.cancel")
	public ReplyInfo<Object> cancel(String id) {
		OfficeWorkInfo o = officeWorkBiz.get(id);
		if (o.getStatus() == OfficeWorkInfo.STATUS_DRAFT//
				|| o.getStatus() == OfficeWorkInfo.STATUS_RUNNING//
				|| o.getStatus() == OfficeWorkInfo.STATUS_PENDING) {
			o.setLastTime(Util.getStdfDate());
			o.setStatus(OfficeWorkInfo.STATUS_CANCEL);
			officeWorkBiz.update(o);
			return ReplyInfo.SUCCESS;
		}
		return Constants.REPLY_WARN_INVALID;
	}

	@RequestMapping("/close.do")
	@Authorized(code = "office.work.close")
	public ReplyInfo<Object> close(String id) {
		OfficeWorkInfo o = officeWorkBiz.get(id);
		if (o.getStatus() == OfficeWorkInfo.STATUS_DONE//
				|| o.getStatus() == OfficeWorkInfo.STATUS_CANCEL) {
			o.setLastTime(Util.getStdfDate());
			o.setStatus(OfficeWorkInfo.STATUS_CLOSED);
			officeWorkBiz.update(o);
			return ReplyInfo.SUCCESS;
		}
		return Constants.REPLY_WARN_INVALID;
	}

	/**
	 * 供首页使用的查询
	 * 
	 * @return
	 */
	@JsonIgnoreProperties(value = { "preWorks" })
	@RequestMapping("/index.do")
	@Authorized(code = "office.work.index")
	public ReplyInfo<Object> index(@Logined LogonI<String> logon, String groupId, String key, String orderBy, int pageNo,
			int pageSize) {
		if (Util.strIsEmpty(groupId)) {
			// 如果没传groupId则取当前用户默认的Group
			OfficeGroupUser g = groupUserBiz.getUserDefaultGroupId(logon.getId());
			if (g != null) {
				groupId = g.getGroupId();
			}
		}
		PagedResult<OfficeWorkInfo> pr = officeWorkBiz.list(//
				groupId, logon.getId(), key, orderBy, pageNo, pageSize);
		for (OfficeWorkInfo o : pr.getList()) {
			o.setOwner(this.getSysUser(o.getOwnerId()));
			// 查询此任务的明细日志
			List<OfficeWorkLog> lt = officeWorkLogBiz.list(o.getId(), o.getOwnerId());
			o.getLogs().clear();
			for (OfficeWorkLog l : lt) {
				o.addLog(l.getTime().substring(0, 10), l);
			}
		}
		return new ReplyInfo<Object>(true, pr);
	}

	/**
	 * 供首页使用的查询
	 * 
	 * @return
	 */
	@JsonIgnoreProperties(value = { "preWorks" })
	@RequestMapping("/list.do")
	@Authorized(code = "office.work.list")
	public ReplyInfo<Object> list(@Logined LogonI<String> logon, String groupId, String key, //
			String ownerId, Short status, String orderBy, int pageNo, int pageSize) {
		if (Util.strIsEmpty(groupId)) {
			// 如果没传groupId则取当前用户默认的Group
			OfficeGroupUser g = groupUserBiz.getUserDefaultGroupId(logon.getId());
			if (g != null) {
				groupId = g.getGroupId();
			}
		}
		PagedResult<OfficeWorkInfo> pr = officeWorkBiz.list(//
				groupId, ownerId, key, status, orderBy, pageNo, pageSize);
		for (OfficeWorkInfo o : pr.getList()) {
			o.setOwner(this.getSysUser(o.getOwnerId()));
			// 查询此任务的明细日志
			// o.setLogs(officeWorkLogBiz.list(o.getId()));
		}
		return new ReplyInfo<Object>(true, pr);
	}
}